package com.szholly.plug.safe.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.itfreer.security.filter.ExcludeUrlConfig;
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Component;

import com.szholly.utils.common.log.LogFactory;
import com.szholly.utils.session.SessionFactory;
import com.szholly.utils.session.provider.ISessionProvider;
import com.szholly.utils.util.CookieUtils;
import com.szholly.utils.util.DateUtils;
import com.szholly.utils.util.StringUtils;
import com.szholly.data.general.QueryMap;
import com.szholly.plug.safe.entity.LogEntity;
import com.szholly.plug.safe.entity.LogService;
import com.szholly.plug.safe.entity.LogTypeDic;
import com.szholly.plug.safe.entity.role.RoleInitHelper;
import com.szholly.plug.safe.entity.user.OrgEntity;
import com.szholly.plug.safe.entity.user.OrgService;
import com.szholly.plug.safe.entity.user.UserEntity;
import com.itfreer.sso.SsoFilter;
import com.itfreer.sso.client.validation.Assertion;

/**
 * 访问权限过滤器
 */
//@Component
public class PowerFilter implements Filter, ApplicationContextAware {

	private static Logger logger = Logger.getLogger(PowerFilter.class);

	protected static ApplicationContext applicationContext;

	@Override
	public void setApplicationContext(ApplicationContext appContext) throws BeansException {
		applicationContext = appContext;
	}

	private ExcludeUrlConfig excludeUrlConfig;

	protected ExcludeUrlConfig getExcludeUrlConfig() {
		if (excludeUrlConfig == null) {
			excludeUrlConfig = applicationContext.getBean(ExcludeUrlConfig.class);
		}
		return excludeUrlConfig;
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {

	}

	@Override
	public void destroy() {

	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		final HttpServletRequest request = (HttpServletRequest) servletRequest;
		final HttpServletResponse response = (HttpServletResponse) servletResponse;

		// 根据参数，过滤请求
		String rqUrl = request.getServletPath();
		if (ExcludeUrlConfig.exclude(getExcludeUrlConfig().getExcludeUrls(), rqUrl)) {
			filterChain.doFilter(request, response);
			return;
		}

		// 获取登录用户
		ISessionProvider session = SessionFactory.getSession();
		UserEntity userEntity = session != null ? (UserEntity) session.getObject(ISessionProvider.UserEntity) : null;
		if (userEntity == null) {
			final HttpSession httpSession = request.getSession(false);
			final Assertion assertion = httpSession != null
					? (Assertion) httpSession.getAttribute(SsoFilter.CONST_SSO_ASSERTION) : null;
			if (assertion == null) {
				throw new AccessDeniedException("访问权限不够！");
			}
			
			String userName = assertion.getPrincipal().getName();
			userEntity = RoleInitHelper.getUser(userName);
			if (userEntity == null) {
				throw new AccessDeniedException("访问权限不够！");
			}
			
			CookieUtils.cancleCookie(request, response, CookieUtils.Security_Tag, null);
			CookieUtils.cancleCookie(request, response, CookieUtils.Security_Url, null);
			
			initUserRole(userEntity, request, response);
		}
		
		// URL调用
		urlResourceDecide(rqUrl, userEntity);
		
		// 如果通过了，则到此执行后续过滤器
		filterChain.doFilter(request, response);
	}

	// 初始化用户角色
	@SuppressWarnings("unchecked")
	private static void initUserRole(UserEntity userEntity, HttpServletRequest request,
			HttpServletResponse response) throws UnsupportedEncodingException {

		RoleInitHelper.getRoles(userEntity);
		// 记录日志
		logLogin(userEntity);
		
		// 将部分信息发送到cookie中
		List<String> functionTag = null;
		List<String> functionUrl = null;
		if(userEntity.getIsSuperAdmin()){
			functionTag = new ArrayList<String>();
			functionUrl = new ArrayList<String>();
			
			functionTag.add("sa");
			functionUrl.add("sa");
		} else {
			// 将功能权限，url权限放到用户的cookie中
			ISessionProvider session = SessionFactory.getSession();
			functionTag = (List<String>)session.getObject(ISessionProvider.Function);
			functionUrl = (List<String>)session.getObject(ISessionProvider.FunctionUrl);
		}
		
		String tagString = "";
		for(String item : functionTag){
			tagString += item+",";
		}
		if(!tagString.equals("")){
			tagString = tagString.substring(0, tagString.length()-1);
		}
		CookieUtils.addCookie(request, response, CookieUtils.Security_Tag, tagString, null, null);
		
		String urlString = "";
		for(String item : functionUrl){
			urlString += item+",";
		}
		urlString = urlString.equals("") ? "" : urlString.substring(0, urlString.length()-1);
		CookieUtils.addCookie(request, response, CookieUtils.Security_Url, urlString, null, null);
		// 用户ID
		CookieUtils.addCookie(request, response, CookieUtils.Security_UserID, userEntity.getUserID(), null, null);
		
		// 用户真实名称
		String name = userEntity.getUserRealName();
		if(StringUtils.IsNullOrSpace(name)){
			CookieUtils.addCookie(request, response, CookieUtils.Security_UserRealName, "", null, null);
		}else{
			name = URLEncoder.encode(name, "utf-8");
			CookieUtils.addCookie(request, response, CookieUtils.Security_UserRealName, name, null, null);
		}
		
		// 单位
		name = userEntity.getDW();
		if(StringUtils.IsNullOrSpace(name)){
			CookieUtils.addCookie(request, response, CookieUtils.Security_UserDw, "", null, null);
		}else{
			name = URLEncoder.encode(name, "utf-8");
			CookieUtils.addCookie(request, response, CookieUtils.Security_UserDw, name, null, null);
		}
		
		// 机构
		name = userEntity.getOrgName();
		if(StringUtils.IsNullOrSpace(name)){
			CookieUtils.addCookie(request, response, CookieUtils.Security_UserOrg, "", null, null);
		}else{
			name = URLEncoder.encode(name, "utf-8");
			CookieUtils.addCookie(request, response, CookieUtils.Security_UserOrg, name, null, null);
		}
		
		// 机构Id
		name = userEntity.getOrgID();
		if(StringUtils.IsNullOrSpace(name)){
			CookieUtils.addCookie(request, response, CookieUtils.Security_Orgbh, "", null, null);
		}else{
			name = URLEncoder.encode(name, "utf-8");
			CookieUtils.addCookie(request, response, CookieUtils.Security_Orgbh, name, null, null);
		}
		
		// 部门
		name = userEntity.getDEPTName();
		if(StringUtils.IsNullOrSpace(name)){
			CookieUtils.addCookie(request, response, CookieUtils.Security_DeptName, "", null, null);
		}else{
			name = URLEncoder.encode(name, "utf-8");
			CookieUtils.addCookie(request, response, CookieUtils.Security_DeptName, name, null, null);
		}
		
		// 部门所在政区
		QueryMap qm = new QueryMap();
		HashMap<String,Object> map = new HashMap<String,Object>();
		map.put(OrgEntity.FIELD_ORGID, userEntity.getOrgID());
		qm.setWhereMap(map);
		OrgEntity org = OrgService.getSingleRef().getEntity(OrgEntity.class, qm);
		if(org != null){
			name = org.getOrgBH();
		}else{
			name = null;
		}
		if(StringUtils.IsNullOrSpace(name)){
			CookieUtils.addCookie(request, response, CookieUtils.Security_Orgbh, "", null, null);
		}else{
			name = URLEncoder.encode(name, "utf-8");
			CookieUtils.addCookie(request, response, CookieUtils.Security_Orgbh, name, null, null);
		}
	}

	/**
	 * 决策资源
	 * 
	 * @param rqUrl
	 * @param authentication
	 */
	@SuppressWarnings("unchecked")
	private void urlResourceDecide(String rqUrl, UserEntity userEntity) {
		String userName = userEntity.getUserName();
		if (userEntity.getIsSuperAdmin()) {
			logger.info("urlResourceDecide 用户:" + userName + "请求资源：" + rqUrl + "通过！");
			logFunction(userEntity, "请求资源：" + rqUrl + "通过！");
		} else {
			List<String> canAccessUrl = (List<String>) SessionFactory.getSession()
					.getObject(ISessionProvider.FunctionUrl);
			if (canAccessUrl == null) {
				logger.info("urlResourceDecide 用户:" + userName + "所授权的资源为空。请求资源：" + rqUrl + "失败！");
				throw new AccessDeniedException("访问权限不够！");
			} else {
				if (ExcludeUrlConfig.exclude(canAccessUrl, rqUrl)) {
					logger.info("urlResourceDecide 用户:" + userName + "请求资源：" + rqUrl + "通过！");
					logFunction(userEntity, "请求资源：" + rqUrl + "通过！");
					return;
				} else {
					logger.info("urlResourceDecide 用户:" + userName + "请求资源：" + rqUrl + "失败！");
					throw new AccessDeniedException("访问权限不够！");
				}
			}
		}
	}

	private void logFunction(UserEntity userEntity, String desc) {
		if (!LogFactory.getlogPara().isLogFuntion()) {
			return;
		}
		ISessionProvider session = SessionFactory.getSession();
		LogEntity log = new LogEntity();
		if (session != null) {
			log.setIP(session.getIp());
		}
		log.setLogDate(DateUtils.convertDateTimeToString(null));
		log.setLogDesc(desc);
		log.setLogType(LogTypeDic.Function);
		if (userEntity != null) {
			log.setUserName(userEntity.getUserRealName());
		}
		LogService.getSingleRef().SaveEntityInThread(log);
	}

	private static void logLogin(UserEntity userEntity) {
		if (!LogFactory.getlogPara().isLogIn()) {
			return;
		}

		// 用户登录日志
		ISessionProvider session = SessionFactory.getSession();
		LogEntity log = new LogEntity();
		if (session != null) {
			log.setIP(session.getIp());
		}
		log.setLogDate(DateUtils.convertDateTimeToString(null));
		log.setLogDesc("登录成功");
		log.setLogType(LogTypeDic.LogIn);
		log.setUserName(userEntity.getUserRealName());
		LogService.getSingleRef().SaveEntityInThread(log);
	}

}